AMF remoting and runtime fixes - #25
Open
neilrackett wants to merge 5 commits into
Open
Conversation
connect() and call() were stubs (somewhatImplemented), so classic
AMF remoting apps - NetConnection.connect(gatewayUrl) +
call('Service.method', responder, ...args) against Zend_Amf / AMFPHP /
FluorineFx-style gateways - could not talk to their backend at all.
- connect(): a null command or non-rtmp url is a remoting gateway
connection; it succeeds immediately (calls are independent HTTP POSTs)
and dispatches NetConnection.Connect.Success asynchronously so listeners
registered right after connect() still receive it. rtmp/rtmpt/rtmps
remain unimplemented and dispatch Connect.Failed.
- call(): serialises arguments with the AVM2 ByteArray AMF codec (AMF3
body behind the 0x11 avmplus marker in an AMF0 envelope), wraps them in
a hand-written remoting packet, POSTs application/x-amf via fetch with
credentials included, parses the response envelope, decodes bodies back
through the same codec, and routes /<id>/onResult|onStatus to the
matching Responder. Native call arguments arrive flat (no rest
collection), so everything after the responder argument is captured
via arguments.
- Faults: HTTP errors, non-AMF responses (misconfigured gateways answering
200 with an HTML error page) and synchronous failures are routed to the
Responder's status callback, falling back to a
NetConnection.Call.Failed netStatus event.
- Implementation notes: ByteArray must be constructed through its AXClass
(its buffer machinery comes from DataBuffer instanceNatives and only
exists on the VM-linked prototype); NetStatusEvent likewise, so property
access from compiled AS3 sees proper runtime traits; .sec is set on the
ByteArray for the AMF codec (same idiom as SharedObject).
- Responder: add invokeResult/invokeStatus helpers encapsulating the
callback invocation.
- Opt-in wire logging via self.__AWAYFL_AMF_DEBUG = true.
Verified end-to-end against a Zend_Amf gateway (login flow, list calls,
fault paths) with an AS3 app built on a Proxy-based AMF service layer.
When an EventDispatcher is constructed with a target argument
(the IEventDispatcher aggregation pattern), Flash reports that target -
not the internal dispatcher - as event.currentTarget during dispatch.
GreenSock (TweenLite/TweenMax v12) dispatches its tween events through an
aggregated EventDispatcher, and typical handler code does
var tween:TweenMax = event.currentTarget as TweenMax;
tween.removeEventListener(event.type, handler);
Without this fix the `as` cast returns null and such handlers crash
(and, being inside the tween render pass, can take the frame loop's
callback chain down with them).
target was already reported through _t; do the same for currentTarget.
…y detached The internal (awayjs) scene graph can diverge from the AS3 display list via orphan/unload management, so removeChild() on a child that is still in the AS3 display list may find the adaptee already detached. Throwing ArgumentError #2025 in that situation erupts through whatever frame callback is currently running - e.g. a tween's onComplete removing a preloader - and can kill the shared ticker, freezing the entire app (rendering continues but no frame events and no input are processed). Warn and treat the child as removed instead. This intentionally deviates from Flash for the divergence case; genuinely removing a never-added child now warns rather than throws, which is the safer failure mode here.
Content that uses custom cursors constructs MouseCursorData before passing it to Mouse.registerCursor(); with the class unlinked, class initialization aborts with 'Class native is not defined: flash.ui.MouseCursorData' - a hard VM error that prevents the SWF's script from running at all, even though registerCursor itself is a harmless no-op here. Link a fresh, working data holder (data/hotSpot/frameRate). The _shumway_flash implementation is not used: it has stale relative imports and notImplemented accessors.
Recent versions of the typings require file extensions in
SaveFilePickerOptions accept maps to be typed as `.${string}`;
the plain string no longer compiles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Flash Remoting (AMF over HTTP) support + related runtime fixes
This PR makes classic AMF remoting apps work under AwayFL: apps built on
NetConnection.connect(gatewayUrl)+call('Service.method', responder, ...args)against Zend_Amf / AMFPHP / FluorineFx-style PHP/.NET gateways.
It was developed by reviving a real-world AS3/Flex-era business app (a
Proxy-based AMF service layer talking to a Zend_Amf backend) and contains one
feature plus four small fixes that the same app surfaced along the way. Happy
to split any of these into separate PRs if preferred — each is an independent
commit touching disjoint files.
Commits
NetConnection: implement Flash Remoting (AMF over HTTP POST)
connect()/call()were stubs. Now: serialisation through the AVM2ByteArray AMF codec (arguments and results stay proper AVM2 objects), a
hand-written remoting packet envelope,
fetchPOST with credentials,fault routing to
Responder.status/NetConnection.Call.Failed, andopt-in wire logging via
self.__AWAYFL_AMF_DEBUG = true.Notable implementation details (each learned the hard way):
ByteArray/NetStatusEventare constructed through their AXClass —raw
newproduces instances without runtime traits (ByteArray's buffermachinery lives in DataBuffer
instanceNatives; event property accessfrom compiled AS3 needs the VM-linked prototype).
...restcollection), socall arguments are collected from
arguments.Connect.Failed(unchanged).EventDispatcherBase: report the aggregation target as
currentTargetFlash reports the
EventDispatcher(target)aggregation target asevent.currentTarget. GreenSock v12 relies on this(
event.currentTarget as TweenMaxreturned null and handlers crashed).DisplayObjectContainer: don't throw #2025 when the adaptee is already
detached — the internal scene graph can diverge from the AS3 display
list; the throw could erupt through a tween
onCompleteand kill theshared ticker (app frozen: rendering continues, no events/input).
Link
flash.ui.MouseCursorData— content constructing it forMouse.registerCursordied with "Class native is not defined", a hard VMerror, even though registerCursor itself is a no-op. Fresh data-holder
implementation (the
_shumway_flashone has stale imports).FileReference: satisfy current
@types/wicg-file-system-access(build fix; extensions must be typed
`.${string}`).Verification
Tested end-to-end against a Zend_Amf gateway with the aforementioned app:
boot, login flow (
authUser/authToken), data list calls, and both faultpaths (unknown method / unknown service), plus browser-automation regression
runs of the full boot→login→data flow.
Companion PR in avm2 (independent, but the same app needs both):
Proxy trap dispatch fix for public-mangled flash_proxy overrides.